##############################################################################
## Replication code for                                                     ##
## Rod Alence, "Civil Society and the African Peer Review Mechanism         ##
## 'Experiment': Evidence from a Survey of Africa-Based Non-Governmental    ##
## Organizations," *The Africa Governance Papers*, 2.3 (May 2023): 154-181. ##
##############################################################################
library(wordcloud)

load("ngo_survey.RData")
## Data from the EISA Survey on Civil Society and the African Peer Review
## Mechanism, 2013--14 (shared with the permission of the Electoral
## Institute for Sustainable Democracy in Africa (EISA)).

## Convenience function:
pctize <- function(x) round(x, digits = 2) * 100

## TABLE 1: Satisfaction with the APRM and with governance quality
sat_resp <- c("satisfied", "very satisfied")
dis_resp <- c("dissatisfied", "very dissatisfied")
## Dichotomous recodes
ngo_survey$aprm_sat <- ngo_survey$q43
levels(ngo_survey$aprm_sat) <- list(dissatisfied = dis_resp,
                                    satisfied = sat_resp)
ngo_survey$gov_sat <- ngo_survey$q41
levels(ngo_survey$gov_sat) <- list(dissatisfied = dis_resp,
                                   satisfied = sat_resp)
table_1 <- table(ngo_survey$aprm_sat, ngo_survey$gov_sat) |>
  proportions() |>
  addmargins(margin = 1:2) |>
  pctize()
table_1_N <- table(ngo_survey$aprm_sat, ngo_survey$gov_sat) |>
  sum()

## Frequencies in text:
## NGOs get constructive response from...
## APRM institutions
table(ngo_survey$q20.dum) |>
  proportions() |>
  pctize()
## Government
table(ngo_survey$q05.dum) |>
  proportions() |>
  pctize()
## NGOs often influence APRM reports
table(ngo_survey$q21.dum) |>
  proportions() |>
  pctize()
## Governance in my country has been directly improved by APRM process
table(ngo_survey$q22.dum) |>
  proportions() |>
  pctize()
## Person on the street knows about the APRM and its aims
table(ngo_survey$q23.dum) |>
  proportions() |>
  pctize()
## Sectoral breakdown of NGOs
table(ngo_survey$sector) |>
  proportions() |>
  pctize()
## Size (full-time staff) breakdown of NGOs
## (See Table A5; staff details not included in replication data.)

## TABLE 2: Satisfaction with APRM and governance, by sector and size
sample_sup <- subset(ngo_survey,
                     !is.na(aprm_sat) & !is.na(gov_sat))
(table_2_N1 <- table(sample_sup$sector))  # answered both
## APRM, by sector
table(sample_sup$sector, sample_sup$aprm_sat) |>
  proportions(margin = 1) |>
  pctize()
## Governance, by sector
table(sample_sup$sector, sample_sup$gov_sat) |>
  proportions(margin = 1) |>
  pctize()
## (Number of full-time staff not included in replication data.)

## FIGURE 1: Satisfaction with APRM and governance, by country
## "Supply" data (by country)
aprm_sat_xn <- tapply(sample_sup$aprm_sat %in% "satisfied",
                      sample_sup$country,
                      mean)
gov_sat_xn  <- tapply(sample_sup$gov_sat %in% "satisfied",
                      sample_sup$country,
                      mean)
supply_xn <- data.frame(country = names(aprm_sat_xn),
                        aprm_sat = aprm_sat_xn,
                        gov_sat = gov_sat_xn,
                        country_N = as.numeric(table(sample_sup$country)))
supply_xn <- supply_xn[order(supply_xn$aprm_sat), ]
ctry_labs <- paste0(supply_xn$country, "\n(n=", supply_xn$country_N, ")")
## JPEG figure
jpeg(file="fig1_supply_tagp.jpg",
     units="in", width=7, height=5, res=300)
par(mar=c(4.1, 6.1, 0.1, 0.1))
plot.new()
plot.window(xlim = range(supply_xn[, c("aprm_sat", "gov_sat")]),
            ylim=c(0.75, 8.5))
mtext("Percentage of NGOs",
      side=1, line=2.5)
mtext(ctry_labs, side=2, line=0, at=1:7, 
      adj=1, las=1)
axis(side=1, at=c(0.1364, seq(0.2, 0.5, by=0.1), 0.5556),
     labels=c("14", 100 * seq(0.2, 0.4, by=0.1), NA, "56"),
     lwd=1.5)
rug(c(supply_xn$aprm_sat, supply_xn$gov_sat), ticksize=0.02)
segments(y0=1:7, y1=1:7,
         x0=supply_xn$gov_sat,
         x1=supply_xn$aprm_sat,
         lwd=1.5)
points(x=supply_xn$aprm_sat, y=1:7, pch=16, cex=1.5)
points(x=supply_xn$gov_sat, y=1:7, pch=21, bg="white", cex=1.5)
legend(x=0.4, y=8.5, 
       legend=c("Satisfied with domestic governance    ", 
                "Satisfied with the APRM"),
       pch=c(21, 16), pt.cex=1.5,
       bty="n",
       horiz=TRUE,
       xjust=0.5)
dev.off()


## TABLE 3: NGOs' perceived influence and satisfaction with role
## Dichotomous recodes
ngo_survey$ngo_sat <- ngo_survey$q42
levels(ngo_survey$ngo_sat) <- list(dissatisfied = dis_resp,
                                    satisfied = sat_resp)
ngo_survey$ngo_infl <- ngo_survey$q06
table_3 <- table(ngo_survey$ngo_infl, ngo_survey$ngo_sat) |>
  proportions() |>
  addmargins(margin = 1:2) |>
  pctize()
table_3_N <- table(ngo_survey$ngo_infl, ngo_survey$ngo_sat) |>
  sum()

## TABLE 4: Satisfaction with APRM and governance, by sector and size
sample_dem <- subset(ngo_survey,
                     !is.na(ngo_infl) & !is.na(ngo_sat))
(table_4_N1 <- table(sample_dem$sector))  # answered both
## NGO influence, by sector
table(sample_dem$sector, sample_dem$ngo_infl) |>
  proportions(margin = 1) |>
  pctize()
## Satisfaction with NGO role, by sector
table(sample_dem$sector, sample_dem$ngo_sat) |>
  proportions(margin = 1) |>
  pctize()
## (Number of full-time staff not included in replication data.)

## FIGURE 2: NGO influence and satisfaction with role, by country
## "Supply" data (by country)
ngo_infl_xn <- tapply(sample_dem$ngo_infl == 1,
                      sample_dem$country,
                      mean)
ngo_sat_xn  <- tapply(sample_dem$ngo_sat %in% "satisfied",
                      sample_dem$country,
                      mean)
demand_xn <- data.frame(country = names(ngo_sat_xn),
                        ngo_infl = ngo_infl_xn,
                        ngo_sat = ngo_sat_xn,
                        country_N = as.numeric(table(sample_dem$country)))
demand_xn <- demand_xn[order(demand_xn$ngo_infl), ]
ctry_labs <- paste0(demand_xn$country, "\n(n=", demand_xn$country_N, ")")
## JPEG figure
jpeg(file="fig2_demand_tagp.jpg",
     units="in", width=7, height=5, res=300)
par(mar=c(4.1, 6.1, 0.1, 0.1))
plot.new()
plot.window(xlim = range(demand_xn[, c("ngo_infl", "ngo_sat")]),
            ylim=c(0.75, 8.5))
mtext("Percentage of NGOs",
      side=1, line=2.5)
mtext(ctry_labs, side=2, line=0, at=1:7, 
      adj=1, las=1)
axis(side=1, at=c(0.061, seq(0.1, 0.7, by=0.2), 0.8243),
     labels=c("6", 100 * seq(0.1, 0.7, by=0.2), "82"),
     lwd=1.5)
rug(c(demand_xn$ngo_infl, demand_xn$ngo_sat), ticksize=0.02)
segments(y0=1:7, y1=1:7,
         x0=demand_xn$ngo_sat,
         x1=demand_xn$ngo_infl,
         lwd=1.5)
points(x=demand_xn$ngo_infl, y=1:7, pch=16, cex=1.5)
points(x=demand_xn$ngo_sat, y=1:7, pch=21, bg="white", cex=1.5)
legend(x=0.4, y=8.5, 
       legend=c("See NGOs as influential    ", 
                "Satisfied with NGOs' role"),
       pch=c(21, 16), pt.cex=1.5,
       bty="n",
       horiz=TRUE,
       xjust=0.5)
dev.off()

## FIGURE 2: NGO influence and satisfaction with role, by country
## "Supply" data (by country)
aprm_sat_xn <- tapply(sample_dem$aprm_sat %in% "satisfied",
                      sample_dem$country,
                      mean)
gov_sat_xn  <- tapply(sample_dem$gov_sat %in% "satisfied",
                      sample_dem$country,
                      mean)
supply_xn <- data.frame(country = names(aprm_sat_xn),
                        aprm_sat = aprm_sat_xn,
                        gov_sat = gov_sat_xn,
                        country_N = as.numeric(table(sample_dem$country)))
supply_xn <- supply_xn[order(supply_xn$aprm_sat), ]
ctry_labs <- paste0(supply_xn$country, "\n(n=", supply_xn$country_N, ")")
## JPEG figure
jpeg(file="fig1_demand_tagp.jpg",
     units="in", width=7, height=5, res=300)
par(mar=c(4.1, 6.1, 0.1, 0.1))
plot.new()
plot.window(xlim = range(supply_xn[, c("aprm_sat", "gov_sat")]),
            ylim=c(0.75, 8.5))
mtext("Percentage of NGOs",
      side=1, line=2.5)
mtext(ctry_labs, side=2, line=0, at=1:7, 
      adj=1, las=1)
axis(side=1, at=c(0.1364, seq(0.2, 0.5, by=0.1), 0.5556),
     labels=c("14", 100 * seq(0.2, 0.4, by=0.1), NA, "56"),
     lwd=1.5)
rug(c(supply_xn$aprm_sat, supply_xn$gov_sat), ticksize=0.02)
segments(y0=1:7, y1=1:7,
         x0=supply_xn$gov_sat,
         x1=supply_xn$aprm_sat,
         lwd=1.5)
points(x=supply_xn$aprm_sat, y=1:7, pch=16, cex=1.5)
points(x=supply_xn$gov_sat, y=1:7, pch=21, bg="white", cex=1.5)
legend(x=0.4, y=8.5, 
       legend=c("Satisfied with domestic governance    ", 
                "Satisfied with the APRM"),
       pch=c(21, 16), pt.cex=1.5,
       bty="n",
       horiz=TRUE,
       xjust=0.5)
dev.off()

## TABLE 5: Support for the continuation of the APRM, by sector and size
## All NGOs
table(ngo_survey$q44.dum) |>
  proportions() |>
  pctize()
sum(table(ngo_survey$q44.dum))  # N
## By sector
table(ngo_survey$sector, ngo_survey$q44.dum) |>
  proportions(margin = 1) |>
  pctize()
table(ngo_survey$sector, ngo_survey$q44.dum) |>
  rowSums()  # N
## (Number of full-time staff not available in replication data.)

## FIGURE 3: Support for the APRM's continuation, by country
sample_support <- subset(ngo_survey, !is.na(q44.dum ))
aprm_support_xn <- tapply(sample_support$q44.dum,
                     sample_support$country,
                     mean)
support_xn <- data.frame(country = names(aprm_support_xn),
                         aprm_support = aprm_support_xn,
                         country_N = as.numeric(table(sample_support$country)))
support_xn <- support_xn[order(support_xn$aprm_support), ]
support_labs <- paste0(support_xn$country, "\n(n=",
                    support_xn$country_N, ")")

jpeg("fig3_aprm_supp_tagp.jpg", units="in", width=7, height=5, res=300)
par(mar=c(4.1, 6.1, 0.1, 0.1))
plot.new()
plot.window(xlim=range(support_xn$aprm_support), ylim=c(0.75, 7.5))
mtext("Percentage of NGOs supporting the APRM's continuation",
      side=1, line=2.5)
mtext(support_labs, side=2, line=0, at=1:7, 
      adj=1, las=1)
segments(x0=min(support_xn$aprm_support), x1=max(support_xn$aprm_support),
         y0=1:7, y1=1:7, lwd=0.8, lty="16")
rug(support_xn$aprm_support, ticksize=0.02)
axis(side=1, at=c(min(support_xn$aprm_support),
                  seq(0.7, 0.9, by=0.1),
                  max(support_xn$aprm_support)),
     labels=100 * c(0.67, seq(0.7, 0.9, by=0.1), 0.91),
     lwd=1.5, cex.axis=0.8)
points(x=support_xn$aprm_support, y=1:7, pch=16, cex=1.2)
dev.off()

## REGRESSION ANALYSIS: Supply, demand, and support
kite_xn <- merge(supply_xn[, -ncol(supply_xn)],
                 demand_xn[, -ncol(demand_xn)],
                 by = "country")
kite_xn <- merge(kite_xn,
                 support_xn[, -ncol(support_xn)],
                 by="country")
## Add supply and demand variables -- some values referenced in text
kite_xn$supply_ratio <- kite_xn$aprm_sat/kite_xn$gov_sat
kite_xn$demand_ratio <- kite_xn$ngo_infl/kite_xn$ngo_sat
## Regression
support_reg <- lm(aprm_support ~ supply_ratio + demand_ratio, data=kite_xn)
summary(support_reg)
kite_xn$fitted_val <- fitted(support_reg)
kite_xn$residual <- resid(support_reg)
## Standardize version
support_reg_z <- lm(scale(aprm_support) ~ scale(supply_ratio) +
                      scale(demand_ratio),
                    data=kite_xn)
summary(support_reg_z)

## FIGURE 4: Actual and predicted NGO support for the APRM
## Country labels
ctry_labs <- paste(kite_xn$country, "\n(", 
                   100 * round(kite_xn$aprm_supp, 2), "%)",
                   sep="")
## "Indifference" contour coordinates
indiff_y <- function(target, x.coords = c(0.75, 2.5)) {
  (target - coef(support_reg)[1] - coef(support_reg)[2] * (x.coords)) /
    coef(support_reg)[3]
}

# Hat
x.coords <- c(0.75, 2.5)
y.9 <- indiff_y(target=.9, x.coords=x.coords)
y.8 <- indiff_y(target=.8, x.coords=x.coords)
y.7 <- indiff_y(target=.7, x.coords=x.coords)
y.6 <- indiff_y(target=.6, x.coords=x.coords)
jpeg("fig4_scatter_tagp.jpg", units="in", height=6, width=6,
    res=300)
par(mar=c(5.1, 4.1, 4.1, 1.6), lheight=.9)
plot(kite_xn$supply_ratio,
     kite_xn$demand_ratio,
     xlim=c(.9, 2.3),
     ylim=c(0.1, 0.7),
     type="n",
     axes=FALSE,
     ylab="Demand (NGO assertiveness)",
     xlab="Supply (APRM opportunity)")
segments(x0=x.coords[1], x1=x.coords[2],
         y0=y.9[1], y1=y.9[2],
         lty="16", lwd=1.5,
         col="grey70")
segments(x0=x.coords[1], x1=x.coords[2],
         y0=y.8[1], y1=y.8[2],
         lty="16", lwd=1.5,
         col="grey70")
segments(x0=x.coords[1], x1=x.coords[2],
         y0=y.7[1], y1=y.7[2],
         lty="16", lwd=1.5,
         col="grey70")
segments(x0=x.coords[1], x1=x.coords[2],
         y0=y.6[1], y1=y.6[2],
         lty="16", lwd=1.5,
         col="grey70")
mtext("90%", side=4, line=0, at=0.5,
      las=1, cex=.8, col="black")
mtext("80%", side=4, line=0, at=0.2,
      las=1, cex=.8, col="black")
mtext("70%", side=1, line=0, at=1.9,
      cex=0.8, col="black")
mtext("60%", side=1, line=0, at=1.13,
      cex=0.8, col="black")
textplot(kite_xn$supply_ratio,
         kite_xn$demand_ratio,
         words=ctry_labs, cex=0.8,
         new=FALSE)
axis(side=1, line=1, at=c(1, 1.5, 2, 2.25),
     labels = c(1, 1.5, 2, 2.25))
axis(side=2, at=c(0.1, 0.3, 0.5, 0.7))
mtext('Diagonal "contour" lines are predicted support for APRM continuation.',
      side=3, line=3, at=0.8, adj=0, cex=.8)
mtext("Numbers in parentheses are actual support for APRM continuation.",
      side=3, line=2, at=0.8, adj=0, cex=.8)
dev.off()


## FIGURE 5: "Kite" graphs of NGO perceptions
## "Kite" ranges
apply(kite_xn[, c("aprm_sat", "gov_sat", "ngo_infl", "ngo_sat")], 2, range)
  
range_lwd <- 1
jpeg("fig5_combined_kites_tagp.jpg",
     units="in", width=7, height=9, res=300)
## Median graph
par(fig=c(0, 1, 0.5, 1), mar=c(4.6, 6.1, 2.6, 6.1))
plot.new()
plot.window(xlim=c(-1, 1), ylim=c(-1,1), asp=1)
polygon(x=c(0, -median(kite_xn$gov_sat),
            0, median(kite_xn$aprm_sat)),
        y=c(-median(kite_xn$ngo_sat), 0,
            median(kite_xn$ngo_infl), 0),
        col="grey80",
        border=NA)
polygon(x=c(0, -1, 0, 1),
        y=c(-1, 0, 1, 0))
polygon(x=c(0, -0.5, 0, 0.5),
        y=c(-0.5, 0, 0.5, 0),
        lty="14",
        lwd=1.5)
lines(x=c(0, 0),
      y=-range(kite_xn$ngo_sat),
      lwd=range_lwd) # NGO "role"
lines(x=-range(kite_xn$gov_sat),
      y=c(0, 0),
      lwd=range_lwd)                  # sat w/ governance
lines(x=c(0, 0),
      y=range(kite_xn$ngo_infl),
      lwd=range_lwd)
lines(x=range(kite_xn$aprm_sat),
      y=c(0,0),
      lwd=range_lwd)
points(0, 0, pch=16)
text(x=-0.3, y=0.3,
     labels = "0.5",
     cex=.8)
text(x=-0.55, y=0.55,
     labels = "1.0",
     cex=.8)
mtext("satisfaction\nwith NGOs' role\nin governance", side=1, line=1,
      at=0, adj=0.5, padj=0, cex=0.8)
mtext("satisfaction\nwith governance", side=2, line=-1,
      las=1, adj=0.5, cex=0.8)
mtext("perceived\n NGO influence\non governance", side=3, line=-0.5,
      at=0, adj=0.5, padj=0, cex=0.8)
mtext("satisfaction with\nAPRM process", side=4, line=-1,
      las=1, adj=0.5, cex=0.8)

mtext('(a) Pooled seven-country "kite"', font=2,
      side=1, line=2.75, adj=0.5, padj=0)

## Country-specific kites
kite_xn <- kite_xn[order(kite_xn$aprm_support, decreasing=TRUE), ]
## List of positions
bot.gap <- 0.05
ver.pos <- bot.gap + (0.5 - bot.gap) * ((0:3) / 3)
kite.pos <- data.frame(left=c(rep(c(0, 1/3, 2/3), 2), 1/3),
                       right=c(rep(c(1/3, 2/3, 1), 2), 2/3),
                       bottom=c(rep(ver.pos[3], 3),
                                rep(ver.pos[2], 3),
                                ver.pos[1]),
                       top=c(rep(ver.pos[4], 3),
                             rep(ver.pos[3], 3),
                             ver.pos[2]))
for (i in 1:nrow(kite_xn)) {
      par(fig=kite.pos[i, ], mar=c(0.1, 0.1, 2.6, 0.1), new=TRUE)
  plot.new()
  plot.window(xlim=c(-0.52, +0.52), ylim=c(-.8,0.52), asp=1)
  polygon(x=c(0, -median(kite_xn$gov_sat),
              0, median(kite_xn$aprm_sat)),
          y=c(-median(kite_xn$ngo_sat), 0,
              median(kite_xn$ngo_infl), 0),
          col="grey80",
          border=NA)
  polygon(x=c(0, -0.5, 0, 0.5),
          y=c(-0.5, 0, 0.5, 0),
          lty="14",
          lwd=1.5)
  lines(x=c(0, 0),
        y=-range(kite_xn$ngo_sat),
        lwd=range_lwd) 
  lines(x=-range(kite_xn$gov_sat),
        y=c(0, 0),
        lwd=range_lwd)   
  lines(x=c(0, 0),
        y=range(kite_xn$ngo_infl),
        lwd=range_lwd)
  lines(x=range(kite_xn$aprm_sat),
        y=c(0,0),
        lwd=range_lwd)
  points(0, 0, pch=16, cex=0.8)
   mtext(paste(kite_xn$country[i], " (",
              round(100 * kite_xn$aprm_support[i]), "%)",
              sep=""),
        side=3, line=0,
        cex=.8)
  polygon(x=c(0, -kite_xn$gov_sat[i], 0, +kite_xn$aprm_sat[i]),
          y=c(-kite_xn$ngo_sat[i], 0, +kite_xn$ngo_infl[i], 0),
          lwd=1.5)
}
par(fig=c(0, 1, 0, bot.gap), mar=c(0, 0, 0, 0), new=TRUE)
plot.new()
text(0.5, 0.5,
     labels='(b) Seven country-specific "kites"',
     font=2)
dev.off()

